/*
SC R*D 满荣 20231031
这个文件是将EEPROM.h做二次封装，对外简单的暴露2个函数
1.读取数据方法ReadEEPROM<T>(int address):这个方法是一个泛型方法，根据数据首地址和类型T来判断读取数据的长度，同时返回读取的数据
2.写入数据方法WriteEEPROM<T>(int address, T value)：这个方法是一个泛型方法，根据数据首地址和类型T来判断写入数据的长度
3.使用方法：将该文件#include后就可以直接使用了
*/

#ifndef _myEEPROM_H_
#define _myEEPROM_H_

#include <Arduino.h>
#include <EEPROM.h>
#include "myModbusRTUSlave.h"

uint16_t Eeprom_Size = 1 * 1024; // EEPROM大小，默认1k字节,当数据比较多时，根据需要可以适当扩大该范围，在ESP32-S3中，最大4k
#define ParameterStartIndex 20
#define ParameterLength 20


template <typename T>
void ReadEEPROM(int startAddress, int numElements, T* values)
{
    EEPROM.begin(Eeprom_Size);
    for (int i = 0; i < numElements; i++) {
        EEPROM.get(startAddress + i * sizeof(T), values[i]);
    }
    EEPROM.end();
}

/// @brief 读取EEPROM中指定地址的内容，经过测试，读取一个int32耗时在3ms左右
/// @tparam T 要读取的数据类型，可自动推断
/// @param address 读取数据的起始地址，注意在EEPROM中，地址是以字节为单位，需要考虑存储数据的数据区域，还要注意EEPROM的大小，超过地址范围可能导致数据错误
/// @return 读取成功返回True，否则返回False
template <typename T>
T ReadEEPROM(int address)
{
    EEPROM.begin(Eeprom_Size);
    T value;
    EEPROM.get(address, value);
    EEPROM.end();
    return value;
}

/// @brief 把数据写入到EEPROM的指定地址中,经过测试，写入一个int32耗时10-30ms，所以需要注意写入时间，在需要写入多个数据时可以考虑将数据组合成结构体来写入。
/// @tparam T 要写入的数据类型，可能自动推断
/// @param address 写入数据的起始地址，注意在EEPROM中，地址是以字节为单位，需要考虑存储数据的数据区域，还要注意EEPROM的大小，超过地址范围可能导致数据错误
/// @param value 写入数据的值，可以是数据、字符、结构体、类
template <typename T>
void WriteEEPROM(int address, T value)
{
    EEPROM.begin(Eeprom_Size);
    EEPROM.put(address, value);
    EEPROM.commit();
    EEPROM.end();
}


/// @brief 保存参数到EEPROM，从保存寄存器20-39保存到EEPROM地址100-139，
void SaveParameter()
{
    EEPROM.begin(Eeprom_Size);
    for (int i = 0; i < ParameterLength; i++)
    {
        EEPROM.put(100 + (i * 2), holdingRegisters[ParameterStartIndex + i]);
    }
    EEPROM.commit();
    EEPROM.end();
}
/// @brief 从EEPROM读取数据，从EEPROM地址100-139读取数据到保持寄存器20-39保
void ReadParameter()
{
    EEPROM.begin(Eeprom_Size);
    for (int i = 0; i < ParameterLength; i++)
    {
        EEPROM.get(100 + (i * 2), holdingRegisters[ParameterStartIndex + i]);
    }
    EEPROM.end();
}
/// @brief 参数初始化
void ParameterInitialize()
{
    holdingRegisters[20] = 250;  // 输入气压上限，单位Kpa
    holdingRegisters[21] = 150;  // 输入气压下限，单位Kpa，高于上限或低于下限则报警
    holdingRegisters[22] = 2000; // 延时时间,单位ms
    holdingRegisters[23] = 150;  // 出气泄漏下限，单位Kpa
    holdingRegisters[24] = 50;   // 调速阀反向判断压力上限(50Kpa)
    holdingRegisters[25] = 200;  // 流量异常判断下限(200mL/min)
    holdingRegisters[26] = 20;   // 泄露压力上限(20Kpa)
    holdingRegisters[27] = 0;
    holdingRegisters[28] = 0;
    holdingRegisters[29] = 0;
    holdingRegisters[30] = 0;
    holdingRegisters[31] = 0;
    holdingRegisters[32] = 0;
    holdingRegisters[33] = 0;
    holdingRegisters[34] = 0;
    holdingRegisters[35] = 0;
    holdingRegisters[36] = 0;
    holdingRegisters[37] = 0;
    holdingRegisters[38] = 0;
    holdingRegisters[39] = 150;
    SaveParameter();
}

#endif